package com.example.controller;

import com.alibaba.fastjson.JSONObject;
import com.example.config.WechatPayConfig;
import com.example.enums.ProductOrderPayTypeEnum;
import com.example.service.ProductOrderService;
import com.wechat.pay.contrib.apache.httpclient.auth.ScheduledUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author yinxin
 * @version 1.0
 * //https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_1.shtml(微信支付签名验证地址)
 * @Description:
 * @date 2022/6/2021:33
 */
@Controller
@RequestMapping("/api/callback/order/v1")
@Slf4j
public class PayCallbackController {

    @Autowired
    private WechatPayConfig wechatPayConfig;

    @Autowired
    private ProductOrderService productOrderService;

    @Autowired
    private ScheduledUpdateCertificatesVerifier verifier;

    /**
     * //构造签名串验证签名
     * - 获取报文
     * - 验证签名（确保是微信传输过来的）
     * - 解密（AES对称解密出原始数据）
     * - 处理业务逻辑
     * - 响应请求
     */
    @RequestMapping("wechat")
    @ResponseBody
    public Map<String, String> wechatPayCallback(HttpServletRequest request, HttpServletResponse response) throws GeneralSecurityException {

        String body = getRequestBody(request);

        String nonceStr = request.getHeader("Wechatpay-Nonce");//随机串
        String signature = request.getHeader("Wechatpay-Signature");//微信传过来的签名
        String serialNo = request.getHeader("Wechatpay-Serial");//证书序列号
        String timestamp = request.getHeader("Wechatpay-Timestamp");//时间戳

        /**
         * 应答时间戳\n
         * 应答随机串\n
         * 应答报文主体\n
         */
        String signStr = Stream.of(timestamp, nonceStr, body).collect(Collectors.joining("\n", "", "\n"));


        HashMap<String, String> map = new HashMap<>(2);
        try {
            boolean isVeritide = verifiedSign(serialNo, signStr, signature);
            if (isVeritide) {
                //解密数据
                String plainBody = decryptBody(body);
                log.info("解密后的明文:{}", plainBody);
                Map<String, String> paramsMap = convertWechatPayMsgToMap(plainBody);
                //处理业务逻辑
                productOrderService.processOrderCallbackMsg(ProductOrderPayTypeEnum.WECHAT_PAY,paramsMap);
                map.put("code", "SUCCESS");
                map.put("message", "成功");
            }
        } catch (UnsupportedEncodingException e) {
            log.error("微信支付回调异常:{}", e.getMessage());
        }

        return map;
    }

    /**
     * 转换body为map
     *
     * @param plainBody
     * @return
     */
    public Map<String, String> convertWechatPayMsgToMap(String plainBody) {
        Map<String, String> map = new HashMap<>();
        JSONObject jsonObject = JSONObject.parseObject(plainBody);

        //商户订单号
        map.put("out_trade_no", jsonObject.getString("out_trade_no"));
        //交易状态
        map.put("trade_state", jsonObject.getString("trade_state"));
        //附加数据(自定义数据)中的 账号
        map.put("account_no", jsonObject.getJSONObject("attach").getString("accountNo"));
        return map;
    }


    /**
     * 解密body的密文
     *
     * @param body
     * @return
     */
    private String decryptBody(String body) throws GeneralSecurityException {
        AesUtil aesUtil = new AesUtil(wechatPayConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8));
        /**
         {
         "id": "EV-2018022511223320873",
         "create_time": "2015-05-20T13:29:35+08:00",
         "resource_type": "encrypt-resource",
         "event_type": "TRANSACTION.SUCCESS",
         "summary": "支付成功",
         "resource": {
         "original_type": "transaction",
         "algorithm": "AEAD_AES_256_GCM",
         "ciphertext": "",
         "associated_data": "",
         "nonce": ""
         }
         }
         */
        JSONObject object = JSONObject.parseObject(body);
        JSONObject resource = object.getJSONObject("resource");
        String ciphertext = resource.getString("ciphertext");
        String associatedData = resource.getString("associated_data");
        String nonce = (String) resource.get("nonce");
        return aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8)
                , ciphertext);
    }

    /**
     *
     * @param serialNo 微信平台-证书序列号
     * @param signStr 自己组装的签名
     * @param signature 微信返回的签名
     * @return
     * @throws UnsupportedEncodingException
     */
    public boolean verifiedSign(String serialNo, String signStr, String signature) throws UnsupportedEncodingException {
        return verifier.verify(serialNo, signStr.getBytes("utf-8"), signature);
    }

    /**
     * 读取请求数据流
     *
     * @param request
     * @return
     */
    private String getRequestBody(HttpServletRequest request) {
        StringBuffer sb = new StringBuffer();
        try (ServletInputStream inputStream = request.getInputStream();
             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        ) {
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            log.error("读取数据流异常:{}", e.getMessage());
        }
        return sb.toString();
    }


}
